'''
Created on 16/10/2011
    
@author: nacho
    '''
    
from pcb import PCB
from cpu import CPU
from swapper import Swapper
from hardDisk import HardDisk
import copy
import sys
    
class OperatingSystem(object):
        '''
        classdocs
        '''
    
    
        def __init__(self, mmu, scheduler,time):
            '''
            Constructor
            '''
            
            self.readyQ = []
            self.ioQ = []
            self.pcbt = {}
            self.mmu = mmu
            self.cpu = CPU(self, self.mmu)
            self.pidCounter = 0
            self.scheduler = scheduler
            self.running = True
            self.timer=time
            
            
            self.swapper = Swapper(self, self.mmu)
            self.pcbInDisk = []
            self.disk = HardDisk()
            
            
        def executeProgram(self, program):
            
            
            pcb = PCB(program, self.pidCounter) #creo un PCB
            self.increasePidCounter() #incremento el contador
            self.pcbt[pcb.processID()] = pcb #inserto el pcb en mi tabla pcbt
            self.readyQ.append(pcb.processID()) #inserto el pid del pcb en la cola de listos           
            self.mmu.load(pcb.processID(), program.fullCode()) ##lo cargo en memoria
            
            
            
        def increasePidCounter(self):
            
            self.pidCounter += 1 #incremento el pidCounter
            
            
            
        def noInstruction(self, pid):
            #matarlo
            
               
            self.exitOS(pid)
           
            if len (self.readyQ) >=  0:
                self.reschedule()
            else:
                print("Mijo")
                self.stopRunning()
            
        def ioInstruction(self, pid):
            
            
            self.ioQ.append(pid) #mando el proceso a la cola de IO
            print("Se puso la instruccion de IO en IOQ")
            self.readyQ.remove(pid)
            if len (self.readyQ) > 0:
              
                self.reschedule()
                
            else:
              
                self.stopRunning()
            
        def exitOS(self, pid):
            
            self.mmu.unload(pid) ###############################
            del self.pcbt[pid] ##unload memory
            self.readyQ.remove(pid)
            
            
        def nextInstruction(self, pid, instrNumber):
            if instrNumber == (len(self.pcbt[pid].program()) - 1):
                
                self.exitOS(pid) #preguntar si hay algo en disco
                
                if len(self.pcbInDisk) > 0:
                    self.cpu.stopRunning()
                    self.swapper.processInDiskNeedMemory()
                
                else:
                    #NO HAY PROCESOS EN DISCO
                    
                    self.reschedule()
                
            else:
                pcb = self.pcbt[pid] #Busco el PCB del PCBT
                pcb.increasePC() #Incremento el numero de instruccion corriente
                self.pcbt[pid] = pcb #Lo Guardo en PCBT
                self.scheduler.reschedule(self.cpu) #Se lo paso a cpu
           
            
        def reschedule(self):
            
            if len (self.readyQ) > 0: ######
                
                self.scheduler.reschedule(self.cpu)
                
            else:
                self.stopRunning()
                
        def click(self):
            
            self.scheduler.click(self,self.readyQ)   
            
            
        def start(self):
            
            if len (self.readyQ) > 0:
                
                self.scheduler.reschedule(self.cpu)
            else:
                
                self.stopRunning()
            
            
        def runningMode(self):
            
            return self.running
        
        def stopRunning(self):
            
            print("No hay procesos pendientes")
            self.running = False
            
            
        def instrNumber(self, pid):
        
            try:
                inum = self.pcbt[pid].instrNumber()
            except KeyError:
                return None
            else:
                return inum       
        
        def calculatePriority(self):
            sys.setrecursionlimit(1500)
            actualQ =copy.copy(self.readyQ)
            if len (self.readyQ) == 0:
                return None
            else:
             
                minPid= actualQ.pop()
                if len (actualQ) > 0:           
                    for actualPid in actualQ:
                        if self.pcbt[actualPid].priority() <= self.pcbt[minPid].priority():
                            minPid=actualPid 
            return minPid
            
        def changeStateToRunning(self, pid):
         
            self.pcbt[pid].changeStateToRunning()
        
        def changeStateToReady(self,pid):
        
            self.pcbt[pid].chageStateToReady()   
        
        
        def firstPID(self):
        
            if len (self.readyQ) > 0:
                actualQ =copy.copy(self.readyQ)
                return actualQ.pop(0)
            
            else:
                self.stopRunning()
        
        def toMature(self,pid):
                 
            self.pcbt[pid].toMature()
            
            

        
        
        def thereIsNoSpaceInMemory(self, pid):
            
            
            self.saveInDisk(pid)
            self.swapper.newProcessNoMemory(pid)
        
        
        def saveInDisk(self, pid):
            
            self.pcbInDisk.append(pid)
            self.disk.save(self.pcbt[pid])
            
            
            
        def swappingSuccesful(self):
            
            print("Succesfully Swapped")
            #self.cpu.startRunning()
            self.running = True
            self.reschedule()
            
            
        def nextToLeave(self):
            
            pid = self.scheduler.nextToLeave(self.pcbInDisk)
            return pid
            
        def countProcessInDisk(self):
            
            return len(self.pcbInDisk)
        
        def choosePidToLoad(self):
            
            return self.scheduler.choosePidToLoad()
            
        def getProgram(self, pid):
            
            return self.pcbt[pid].program()
            
            
        def first(self):
            
            return self.pcbInDisk[0]
        
        def mostPriority(self):
            
            actualPid = self.pcbInDisk[0]
            
            for pid in self.pcbInDisk:
                
                if self.pcbt[actualPid].priority() <= self.pcbt[pid].priority():
                
                    pass
            
                else:
                    
                    actualPid = pid
                    
            return actualPid
        
        
        def lessPriority(self, aList):
            
            actualPid = self.pcbt[aList[0]]
            
            for a in aList:
                
                if self.pcbt[actualPid].priority() < self.pcbt[a].priority():
                    
                    actualPid = a 
                    
            return self.pcbt[actualPid].priority()
        
        
        def hasMorePriorityThanLesserInMemory(self, pid):
            actualQ =copy.copy(self.readyQ)
            pcbInMemory = actualQ.removeAll(self.pcbInDisk)
            lessPriority = self.lessPriority(pcbInMemory)
            
            return self.pcbt[pid].priority < lessPriority
            
                
                
        
        def doesItDeserveMemory(self, pid):
            
            return self.scheduler.deserveMemory(pid, self)
        
        
        def removeFromDisk(self, pid):
            
            self.pcbInDisk.remove(pid)
            self.disk.delete(self.pcbt[pid])
        
        
        
            
            
        
        
            
        
            
           
            
            
            
            
        
            
            
            
            